using System;
using System.Collections.Generic;

using Atomic.Libraries;
using Atomic.Structures;

namespace Atomic.Clusters
{
	[Serializable]
	public class ClusterFunctionFactor
	{
		private Dictionary<Atom, double> values;

		public ClusterFunctionFactor(IEnumerable<Atom> atoms, int index)
			: this(new ReadOnlyList<Atom>(atoms), index)
		{
		}

		internal ClusterFunctionFactor(ReadOnlyList<Atom> atoms, int index)
		{
			int m = atoms.Count;
			if (index < 0 || index > m - 2)
			{
				throw new ArgumentException();
			}
			double a = 2.0 * Math.PI * Math.Ceiling(0.5 * (1 + index)) / m;

			// Go through all possible values of sigma (i.e. admissible atoms).
			values = new Dictionary<Atom, double>();
			for (int i = 0; i < m; i++)
			{
				double x = a * i;
				if (index % 2 == 0)
				{
					x = Math.Cos(x);
				}
				else
				{
					x = Math.Sin(x);
				}
				values[atoms[i]] = -x;
			}

			Atoms = atoms;
			Index = index;
		}

		public double Value(Atom atom)
		{
			double value;
			if (!values.TryGetValue(atom, out value))
			{
				throw new ArgumentException("The cluster isn't defined on the specified atom."); 
			}

			return value;
		}

		public ReadOnlyList<Atom> Atoms
		{
			get;
			private set;
		}

		public int Index
		{
			get;
			private set;
		}
	}
}
